package study.service.blog;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import study.domain.attachment.Attachment;
import study.domain.blog.Comment;
import study.domain.blog.Inbox;
import study.domain.blog.InboxId;
import study.domain.blog.Post;
import study.domain.user.User;
import study.repository.blog.CommentRepository;
import study.repository.blog.InboxRepository;
import study.repository.blog.PostRepository;
import study.service.attachment.AttachmentService;

import com.google.common.collect.Lists;

@Slf4j
@Service
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public class BlogService {

	private static final String ATTACHMENT_CATEGORY = "blog";

	@Resource(name = "postRepository")
	private PostRepository postRepository;

	@Resource(name = "friendService")
	private FriendService friendService;

	@Resource(name = "inboxRepository")
	private InboxRepository inboxRepository;

	@Resource(name = "commentRepository")
	private CommentRepository commentRepository;

	@Resource(name = "attachmentService")
	private AttachmentService attachmentService;

	public List<Post> feeds(Long userId, int maxSize, Long lastPostId) {
		InboxId id = new InboxId(userId);
		Inbox inbox = inboxRepository.findOne(id);
		if (inbox == null) {
			inbox = new Inbox(id);
			inboxRepository.save(inbox);
		}
		List<Long> postIds = inbox.getPostIds();
		if (lastPostId != null) {
			List<Long> sortedIds = Lists.newArrayList();
			for (Long postId : postIds) {
				if (postId.compareTo(lastPostId) >= 0) {
					continue;
				}
				sortedIds.add(postId);
			}
			postIds = sortedIds;
		}
		boolean isDirty = false;
		List<Post> posts = Lists.newArrayList();
		for (Long postId : postIds) {
			if (posts.size() == maxSize) {
				break;
			}
			Post post = postRepository.findOne(postId);
			if (post == null) {
				log.error("post '{}' NOT exists", postId);
				continue;
			}
			if (!post.isDeleted()) {
				posts.add(post);
			} else {
				if (inbox.deletePost(post)) {
					isDirty = true;
				}
			}
		}
		if (isDirty) {
			inboxRepository.save(inbox);
		}
		return posts;
	}

	public List<Post> getPosts(Long userId) {
		return postRepository.findByUser_UserId(userId);
	}

	public Post getPost(Long id) {
		return postRepository.findOne(id);
	}

	@Transactional(readOnly = false)
	public Post addPost(User user, Post post, List<String> attachmentIds) {
		post.setUser(user);
		if (attachmentIds != null && attachmentIds.size() > 0) {
			List<Attachment> attachments = attachmentService.findAll(
					attachmentIds, user.getUserId(), ATTACHMENT_CATEGORY);
			log.debug("attachmentIds={}, attachments={}", attachmentIds,
					attachments);
			post.setAttachments(attachments);
		}
		postRepository.save(post);
		addToInbox(post);
		return post;
	}

	private void addToInbox(Post post) {
		List<User> users = Lists.newArrayList();
		users.add(post.getUser());
		users.addAll(friendService.findAllFollower(post.getUser()));
		for (User user : users) {
			Inbox inbox = inboxRepository.findOne(new InboxId(user));
			if (inbox == null) {
				inbox = new Inbox(user);
			}
			inbox.addPost(post);
			inboxRepository.save(inbox);
			log.debug("user '{}' inbox {}", user, inbox.getDataListSize());
		}
	}

	@Transactional(readOnly = false)
	public void removePost(Post post) {
		post.setDeleted(true);
		post.setDeletedDate(new Date());
		postRepository.save(post);
		removeFromInbox(post);
	}

	private void removeFromInbox(Post post) {
		List<User> users = Lists.newArrayList();
		users.add(post.getUser());
		users.addAll(friendService.findAllFollower(post.getUser()));
		for (User user : users) {
			Inbox inbox = inboxRepository.findOne(new InboxId(user));
			if (inbox == null) {
				continue;
			}
			inbox.deletePost(post);
			inboxRepository.save(inbox);
		}
	}

	@Transactional(readOnly = false)
	public Comment addComment(User user, Long postId, String contents) {
		Post post = getPost(postId);
		if (post == null)
			return null;

		Comment comment = new Comment();
		comment.setUser(user);
		comment.setPost(post);
		comment.setContents(contents);
		commentRepository.save(comment);

		// 댓글 개수 변경
		postRepository.updateCommentCount(post);
		return comment;
	}
}
